package com.cl.utility.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.util.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.NumberFormat;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author liddhappy
 * @className ConvertUtils
 * @description 转换
 * @content :object to byte、short、int、long,float、double,char,boolean
 * hashMap,list,
 * localDate,bigDecimal,number,Enum
 * @date 2022/4/26 21:45
 */
public class ConvertUtils {
    public static String objectAsString(final Object object) {
        return object != null ? object.toString() : null;
    }

    public static String objectAsString(final Object object, String defaultValue) {
        return objectAsString(object) == null ? defaultValue : objectAsString(object);
    }

    /**
     * string true -> boolean true string false ->boolean false
     * integer 1->true  integer 0 ->false
     *
     * @param object
     * @return
     */
    public static Boolean objectAsBoolean(final Object object) {
        if (object != null) {
            if (object instanceof Boolean) {
                return (Boolean) object;
            } else if (object instanceof String) {
                return Boolean.valueOf((String) object);
            } else if (object instanceof Number) {
                Number number = (Number) object;
                return (number.intValue() != 0) ? Boolean.TRUE : Boolean.FALSE;
            }
        }
        return null;
    }

    public static Number objectAsNumber(final Object object) {
        if (object != null) {
            if (object instanceof Number) {
                return (Number) object;
            } else if (object instanceof Boolean) {
                Boolean flag = (Boolean) object;
                return flag ? 1 : 0;
            } else if (object instanceof String) {
                try {
                    String string = (String) object;
                    return NumberFormat.getInstance().parse(string);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public static Byte objectAsByte(final Object object) {
        Number result = objectAsNumber(object);
        if (result == null) {
            return null;
        } else if (result instanceof Byte) {
            return (Byte) result;
        }
        return Byte.valueOf(result.byteValue());
    }

    public static byte objectAsByteValue(final Object object) {
        return objectAsByte(object) == null ? 0 : objectAsByte(object).byteValue();
    }

    public static Short objectAsShort(final Object object) {
        Number number = objectAsNumber(object);
        if (number == null) {
            return null;
        } else if (number instanceof Short) {
            return (Short) number;
        }
        return Short.valueOf(number.shortValue());
    }

    public static short objectAsShortValue(final Object object) {
        return objectAsShort(object) == null ? 0 : objectAsShort(object).shortValue();
    }

    public static Integer objectAsInteger(final Object object) {
        Number number = objectAsNumber(object);
        if (number == null) {
            return null;
        } else if (number instanceof Integer) {
            return (Integer) number;
        }
        return Integer.valueOf(number.intValue());
    }

    public static int objectAsIntValue(final Object object) {
        return objectAsInteger(object) == null ? 0 : objectAsInteger(object).intValue();
    }

    public static Long objectAsLong(final Object object) {
        Number number = objectAsNumber(object);
        if (number == null) {
            return null;
        } else if (number instanceof Long) {
            return (Long) number;
        }
        return Long.valueOf(number.longValue());
    }

    public static long objectAsLongValue(final Object object) {
        return objectAsLong(object) == null ? 0L : objectAsLong(object).longValue();
    }

    public static Float objectAsFloat(final Object object) {
        Number number = objectAsNumber(object);
        if (number == null) {
            return null;
        } else if (number instanceof Float) {
            return (Float) number;
        }
        return Float.valueOf(number.floatValue());
    }

    public static float objectAsFloatValue(final Object object) {
        return objectAsFloat(object) == null ? 0f : objectAsFloat(object).floatValue();
    }

    public static Double objectAsDouble(final Object object) {
        Number number = objectAsNumber(object);
        if (number == null) {
            return null;
        } else if (number instanceof Double) {
            return (Double) number;
        }
        return Double.valueOf(number.doubleValue());
    }

    public static double objectAsDoubleValue(final Object object) {
        return objectAsDouble(object) == null ? 0d : objectAsDouble(object).doubleValue();
    }

    public static BigInteger objectAsBigInteger(final Object object) {
        return objectAsLong(object) == null ? BigInteger.ZERO : BigInteger.valueOf(objectAsLong(object).longValue());
    }

    public static BigDecimal objectAsBigDecimal(final Object object) {
        return objectAsDouble(object) == null ? BigDecimal.ZERO :
                BigDecimal.valueOf(objectAsDouble(object).doubleValue());
    }

    public static LocalDate objectAsLocalDate(final Object object) {
        return LocalDate.parse(object.toString(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

    public static Character objectAsChar(final Object object) {
        return objectAsChar(object, null);
    }

    public static Character objectAsChar(Object object, Character defaultValue) {
        if (null == object) {
            return defaultValue;
        }
        if (object instanceof Character) {
            return (Character) object;
        }
        final String objectStr = objectAsString(object, null);
        return !StringUtils.isEmpty(objectStr) ? objectStr.charAt(0) : defaultValue;
    }

    /**
     * 转换Enum 对象
     *
     * @param clazz        enum Class
     * @param object       对象
     * @param defaultValue 默认值
     * @return Enum
     */
    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object object, E defaultValue) {
        if (object == null) {
            return defaultValue;
        }
        if (clazz.isAssignableFrom(object.getClass())) {
            E myE = (E) object;
            return myE;
        }
        final String objectStr = objectAsString(object, null);
        if (StringUtils.isEmpty(objectStr)) {
            return defaultValue;
        }
        try {
            return Enum.valueOf(clazz, objectStr);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * 转换失败给定默认值 null
     *
     * @param clazz  Enum Class
     * @param object 对象
     * @return Enum
     */
    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object object) {
        return toEnum(clazz, object, null);
    }

    /**
     * 单个对象转换
     *
     * @param object 对象
     * @param clz    转换类型
     * @return
     */
    public static <T> T convert(final Object object, Class<T> clz) {
        T result = null;
        if (Boolean.class.equals(clz) || boolean.class.equals(clz)) {
            result = (T) objectAsBoolean(object);
        } else if (Byte.class.equals(clz) || byte.class.equals(clz)) {
            result = (T) objectAsByte(object);
        } else if (String.class.equals(clz)) {
            result = (T) objectAsString(object);
        } else if (Short.class.equals(clz) || short.class.equals(clz)) {
            result = (T) objectAsShort(object);
        } else if (Long.class.equals(clz) || long.class.equals(clz)) {
            result = (T) objectAsLong(object);
        } else if (Integer.class.equals(clz) || int.class.equals(clz)) {
            result = (T) objectAsInteger(object);
        } else if (BigInteger.class.equals(clz) || BigInteger.class.equals(clz)) {
            result = (T) objectAsBigInteger(object);
        } else if (Float.class.equals(clz) || float.class.equals(clz)) {
            result = (T) objectAsFloat(object);
        } else if (Double.class.equals(object) || double.class.equals(clz)) {
            result = (T) objectAsDouble(object);
        } else if (BigDecimal.class.equals(clz) || BigDecimal.class.equals(clz)) {
            result = (T) objectAsBigDecimal(object);
        } else if (LocalDate.class.equals(clz)) {
            result = (T) objectAsLocalDate(object);
        } else {
            if (object instanceof String) {
                result = JSON.parseObject(object.toString(), clz);
            }
        }
        return result;
    }

    public static <T> List<T> converts(List list, final Class<T> clazz) {
        if (StringUtils.isEmpty(list)) {
            return null;
        }
        List<T> resultList = new ArrayList<>();
        list.forEach(element -> {
            resultList.add(convert(element, clazz));
        });
        return resultList;
    }

    /**
     * 半角转全角
     *
     * @param input String.
     * @return 全角字符串.
     */
    public static String toSBC(String input) {
        return toSBC(input, null);
    }

    /**
     * 半角转全角
     *
     * @param input         String
     * @param notConvertSet 不替换的字符集合
     * @return 全角字符串.
     */
    public static String toSBC(String input, Set<Character> notConvertSet) {
        char c[] = input.toCharArray();
        for (int i = 0; i < c.length; i++) {
            if (null != notConvertSet && notConvertSet.contains(c[i])) {
                // 跳过不替换的字符
                continue;
            }

            if (c[i] == ' ') {
                c[i] = '\u3000';
            } else if (c[i] < '\177') {
                c[i] = (char) (c[i] + 65248);

            }
        }
        return new String(c);
    }

    /**
     * 全角转半角
     *
     * @param input String.
     * @return 半角字符串
     */
    public static String toDBC(String input) {
        return toDBC(input, null);
    }

    /**
     * 替换全角为半角
     *
     * @param text          文本
     * @param notConvertSet 不替换的字符集合
     * @return 替换后的字符
     */
    public static String toDBC(String text, Set<Character> notConvertSet) {
        char c[] = text.toCharArray();
        for (int i = 0; i < c.length; i++) {
            if (null != notConvertSet && notConvertSet.contains(c[i])) {
                // 跳过不替换的字符
                continue;
            }

            if (c[i] == '\u3000') {
                c[i] = ' ';
            } else if (c[i] > '\uFF00' && c[i] < '\uFF5F') {
                c[i] = (char) (c[i] - 65248);
            }
        }
        String returnString = new String(c);

        return returnString;
    }

    /**
     * 数字金额大写转换 先写个完整的然后将如零拾替换成零
     *
     * @param n 数字
     * @return 中文大写数字
     */
    public static String digitUppercase(double n) {
        String[] fraction = {"角", "分"};
        String[] digit = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
        String[][] unit = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};

        String head = n < 0 ? "负" : "";
        n = Math.abs(n);

        String s = "";
        for (int i = 0; i < fraction.length; i++) {
            s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
        }
        if (s.length() < 1) {
            s = "整";
        }
        int integerPart = (int) Math.floor(n);

        for (int i = 0; i < unit[0].length && integerPart > 0; i++) {
            String p = "";
            for (int j = 0; j < unit[1].length && n > 0; j++) {
                p = digit[integerPart % 10] + unit[1][j] + p;
                integerPart = integerPart / 10;
            }
            s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
        }
        return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$"
                , "零元整");
    }

    /**
     * Object to map
     *
     * @param object 对象类需要有public无参构造，字段属性需要是public并且内部类也需要这样.
     * @return
     */
    public static HashMap<String, Object> objectToMap(Object object) {
        if (object == null) {
            return null;
        } else {
            return JSONObject.parseObject(JSONObject.toJSONString(object), HashMap.class);
        }
    }

    /**
     * map to object
     * 使用Apache中的BeanUtils类，导入commons-beanutils包
     *
     * @return
     */
    public static Object mapToObject(Map<String, Object> map, Class<?> beanClass) throws InstantiationException,
            IllegalAccessException, InvocationTargetException {
        if (map == null) {
            return null;
        } else {
            Object obj = beanClass.newInstance();
            org.apache.commons.beanutils.BeanUtils.populate(obj, map);
            return obj;
        }
    }

}
